use crate::action_factory::{ActionTrait, ActionData};
use log::*;
use simple_error::*;
use crate::action_do::{executor_fail, executor_recover};
use std::process::Command;

pub struct ActionPing {
    task:ActionData
}

impl ActionPing {
    fn ping_command(&self) -> String {
        let task_conf = &self.task.task_action;
        let r = if cfg!(target_os = "windows") {
            let ping_ms = task_conf.timeout.to_string();
            Command::new("cmd")
                .args(&["/C", "chcp 437","&&","ping","-w",&ping_ms,
                    task_conf.target.as_str()])
                .output()
        } else {
            let ping_timeout:f32 = (task_conf.timeout as f32 / 1000f32);
            let ping_timeout = ping_timeout.to_string();
            Command::new("sh")
                .arg("-c")
                .args(&["ping","-c4", "-w",&ping_timeout, task_conf.target.as_str()])
                .output()
        };

        match r {
            Ok(e) => {
                let rutf8 = String::from_utf8_lossy(e.stdout.as_slice());
                let to_str = rutf8.to_string();
                if cfg!(target_os = "windows") {
                    if to_str.contains("Request timed out") {
                        String::from("failed:Request timed out.")
                    }else {
                        to_str.replace("Active code page: 437", "")
                    }
                }else {
                    if to_str.contains("100% packet loss") {
                        String::from("failed:Request timed out.")
                    }else {
                        to_str
                    }
                }
            },
            Err(e) => {
                let error = format!("run command error:{}",e);
                error
            }
        }
    }
}

impl ActionTrait for ActionPing {
    fn id(&self) -> i32 {
        self.task.id
    }

    fn name(&self) -> &str {
        self.task.name.as_str()
    }

    fn append_data(&mut self, data: ActionData) {
        self.task = data;
    }

    fn executor(&mut self) {
        info!("start ping action:{} id:{}...",self.task.id,self.task.name);

        let task_conf = &self.task.task_action;
        // 开始PING
        let output = String::from(self.ping_command());
        if output.len() >= 0 && task_conf.output_result {
            if output.contains("failed") {
                warn!("ping task failed,run failed...");
                self.task.do_failed();
            }else {
                info!("ping result:{}",output);
                self.task.do_recover();
            }
        }
    }
}

pub fn new_ping(data: ActionData) -> ActionPing {
    ActionPing { task:data }
}